package com.woniuxy.userservice.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Snowflake;
import com.aliyun.tea.TeaException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.core.exception.WoniuxyException;
import com.woniuxy.core.model.Result;
import com.woniuxy.core.status.OrderState;
import com.woniuxy.core.status.UserState;
import com.woniuxy.core.util.DateUtil;
import com.woniuxy.core.util.MyJwtUtil;
import com.woniuxy.userclient.client.OrderFeignClient;
import com.woniuxy.userclient.client.dto.CoachListOrderDto;
import com.woniuxy.userclient.client.dto.VenueListOrderDto;
import com.woniuxy.userdao.mapper.UserInfoMapper;
import com.woniuxy.userdao.model.UserInfo;
import com.woniuxy.usermodel.CoachListUserDto;
import com.woniuxy.usermodel.dto.*;
import com.woniuxy.usermodel.form.*;
import com.woniuxy.userservice.exception.UserInfoException;
import com.woniuxy.userservice.service.UserInfoService;
import com.woniuxy.userservice.util.AuthUser;
import com.woniuxy.userservice.util.ORCIdCardUtil;
import com.woniuxy.util.MyOssUtil;
import com.woniuxy.util.MyRedisKeyUtil;
import com.woniuxy.util.MyRedisUtil;
import com.woniuxy.util.PageInfo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 冉杰
 * @since 2024-01-15
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private MyRedisKeyUtil myRedisKeyUtil;
    @Autowired
    private MyRedisUtil myRedisUtil;
    @Autowired
    private MyOssUtil myOssUtil;
    @Autowired
    private OrderFeignClient ofc;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 用户注册
     * @param form
     */
    @Override
    public void userRegister(UserRegisterForm form){
        String total = myRedisUtil.get(myRedisKeyUtil.errorTotal(form.getUserPhone()));
        //防止非法循环匹配验证码
        if (StringUtils.hasLength(total)&&Integer.parseInt(total)>=5){
            myRedisUtil.del(myRedisKeyUtil.registerCodeKey(form.getUserPhone()));
            myRedisUtil.del(myRedisKeyUtil.errorTotal(form.getUserPhone()));
            throw new UserInfoException(40006,"超过最大错误限次");
        }
        if (!form.getCode().equals(myRedisUtil.get(myRedisKeyUtil.registerCodeKey(form.getUserPhone())))){
            if (!myRedisUtil.exists(myRedisKeyUtil.errorTotal(form.getUserPhone()))){
                myRedisUtil.set(myRedisKeyUtil.errorTotal(form.getUserPhone()),"1",2*60);
            }else {
                myRedisUtil.increment(myRedisKeyUtil.errorTotal(form.getUserPhone()));
            }
            throw new UserInfoException(40004,"验证码错误");
        }
        boolean flag1 = new LambdaQueryChainWrapper<UserInfo>(getBaseMapper())
                .eq(UserInfo::getUserAccount, form.getUserAccount()).exists();
        if (flag1) throw new UserInfoException(40005,"账号已占用");
        boolean flag2 = new LambdaQueryChainWrapper<UserInfo>(getBaseMapper())
                .eq(UserInfo::getUserPhone, form.getUserPhone()).exists();
        if (flag2) throw new UserInfoException(40001,"手机号已被注册");
        UserInfo addUserInfo = BeanUtil.toBean(form, UserInfo.class);
        addUserInfo.setUserState(UserState.IS_ENABLE.getState());//可用状态
        addUserInfo.setAuthState(UserState.IS_NOT_AUTH.getState());//待认证状态
        addUserInfo.setCreateTime(DateUtil.dateTimeToString(new Date()));
        save(addUserInfo);
        //删除缓存里的验证码
        myRedisUtil.del(myRedisKeyUtil.registerCodeKey(form.getUserPhone()));
    }

    /**
     *
     * @param form
     * @return
     */
    @Override
    public UserLoginDto userCodeLogin(UserPhoneLoginForm form) {
        UserInfo userInfo = new LambdaQueryChainWrapper<UserInfo>(getBaseMapper())
                .eq(UserInfo::getUserPhone, form.getUserPhone()).one();
        if (null==userInfo) throw new UserInfoException(40007,"手机号还未注册，请先注册");
        if (userInfo.getUserState()==UserState.IS_DISABLED.getState()) throw new UserInfoException(40008,"账号禁用，禁止登录");
        String total = myRedisUtil.get(myRedisKeyUtil.errorTotal(form.getUserPhone()));
        //防止非法循环匹配验证码
        if (StringUtils.hasLength(total)&&Integer.parseInt(total)>=5){
            myRedisUtil.del(myRedisKeyUtil.loginCodeKey(form.getUserPhone()));
            myRedisUtil.del(myRedisKeyUtil.errorTotal(form.getUserPhone()));
            throw new UserInfoException(40006,"超过最大错误限次");
        }
        if (!form.getCode().equals(myRedisUtil.get(myRedisKeyUtil.loginCodeKey(form.getUserPhone())))){
            if (!myRedisUtil.exists(myRedisKeyUtil.errorTotal(form.getUserPhone()))){
                myRedisUtil.set(myRedisKeyUtil.errorTotal(form.getUserPhone()),"1",5*60);
            }else {
                myRedisUtil.increment(myRedisKeyUtil.errorTotal(form.getUserPhone()));
            }
            throw new UserInfoException(40004,"验证码错误");
        }
        UserLoginDto dto = BeanUtil.toBean(userInfo, UserLoginDto.class);
        //删除缓存里的验证码
        myRedisUtil.del(myRedisKeyUtil.loginCodeKey(form.getUserPhone()));
        return dto;
    }

    /**
     * 用户账号密码登录
     * @param form
     * @return
     */
    @Override
    public UserLoginDto userAccountLogin(UserAccountLoginForm form) {
        UserInfo userInfo = new LambdaQueryChainWrapper<UserInfo>(getBaseMapper())
                .eq(UserInfo::getUserAccount, form.getUserAccount()).one();
        if (null == userInfo) throw new UserInfoException(40001,"账号尚未注册");
        if (userInfo.getUserState()==UserState.IS_DISABLED.getState()) throw new UserInfoException(40002,"账号被禁用");
        if (!userInfo.getUserPass().equals(form.getUserPass())) throw new UserInfoException(40003,"用户名与密码不匹配");
        UserLoginDto dto = BeanUtil.toBean(userInfo, UserLoginDto.class);
        return dto;
    }

    /**
     * 用户上传修改头像
     * @param updateFile
     * @param userId
     * @throws IOException
     */
    @Override
    public void updateUserAvatar(MultipartFile updateFile, Integer userId) throws IOException {
        UserInfo userInfo = getById(userId);
        if (null == userInfo) throw new UserInfoException(40004, "用户不存在");
        if (userInfo.getUserState()==UserState.IS_DISABLED.getState()) throw new UserInfoException(40005, "用户被禁用");
        String type = FileTypeUtil.getType(updateFile.getInputStream());
        if (!type.equals("jpg") && !type.equals("png")) throw new UserInfoException(40006, "图片格式异常");
        String oldFileName = FileUtil.getName(userInfo.getUserAvatar());//保存原文件名
        //先上传新文件，再修改数据库，并把原来的文件删掉
        String fileName = new Snowflake(1, 1).nextIdStr();
        fileName = fileName + "." + type;
        String url = myOssUtil.uploadFile(updateFile.getInputStream(), fileName, "ranjie11");
        //更新数据库
        try {
            userInfo.setUserAvatar(url);
            updateById(userInfo);
        } catch (Exception e) {
            //应该把上传了的文件删掉
            myOssUtil.deleteFile("ranjie11", fileName);
            throw new RuntimeException(e);
        }
        //把原来的文件删除
        if (!ObjectUtils.isEmpty(oldFileName)) myOssUtil.deleteFile("ranjie11", oldFileName);
    }

    /**
     * 管理员查看所有用户
     * @param form
     * @return
     */
    @Override
    public PageInfo<AdminListUserDto> adminListUsers(AdminListUserForm form) {
        Long current = form.getCurrent();
        Long size = form.getSize();
        //开启分页
        Page<UserInfo> page = new Page<>(current==null?1l:current, size==null?6l:size);
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<UserInfo>()
                .eq(!ObjectUtils.isEmpty(form.getUserPhone()),UserInfo::getUserPhone,form.getUserPhone())
                .eq(!ObjectUtils.isEmpty(form.getUserAccount()),UserInfo::getUserAccount,form.getUserAccount());
        getBaseMapper().selectPage(page,wrapper);
        List<UserInfo> userInfos = page.getRecords();
        List<AdminListUserDto> list = BeanUtil.copyToList(userInfos, AdminListUserDto.class);
        PageInfo<AdminListUserDto> pageInfo = BeanUtil.toBean(page, PageInfo.class);
        pageInfo.setPages(page.getPages());
        pageInfo.setList(list);
        return pageInfo;
    }

    /**
     * 教练查看自己学员
     * @param form
     * @param coachId 教练id
     * @return
     */
    @Override
    public List<CoachListUserDto> coachListUser(CoachListUserForm form, Integer coachId) {
        //通过教练id查找其订单,订单中是已付了款状态的就是正在学习中的学员，如果学习完成了订单状态是已完成
        Result<List<CoachListOrderDto>> res1 = ofc.findByCoachId(coachId);
        if (!res1.getFlag()) throw new UserInfoException(res1.getCode(),res1.getMsg());
        List<CoachListOrderDto> data = res1.getData();
        if (ObjectUtils.isEmpty(data)) return null;
        //只需要状态是已付款的订单
        List<CoachListOrderDto> orders = data.stream().filter(o -> o.getOrderState() == OrderState.IS_PAID.getState()).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(orders)) return null;
        List<UserInfo> userInfos = list(new LambdaQueryWrapper<UserInfo>()
                .eq(!ObjectUtils.isEmpty(form.getUserName()), UserInfo::getUserName, form.getUserName())
                .eq(!ObjectUtils.isEmpty(form.getUserPhone()), UserInfo::getUserPhone, form.getUserPhone()));
        if (ObjectUtils.isEmpty(userInfos))  return null;

        List<CoachListUserDto> list = new ArrayList<>();
        for (CoachListOrderDto order : orders) {
            CoachListUserDto dto = BeanUtil.toBean(order, CoachListUserDto.class);
            UserInfo userInfo = getById(order.getUserId());
            dto.setUserAvatar(userInfo.getUserAvatar());
            dto.setUserName(userInfo.getUserName());
            dto.setSex(userInfo.getUserSex());
            dto.setTypeId(order.getOrderType());
            dto.setTypeName(order.getTypeName());
            list.add(dto);
        }
        List<CoachListUserDto> dtos = new ArrayList<>();
        for (UserInfo userInfo : userInfos) {
            for (CoachListUserDto coachListUserDto : list) {
                if (userInfo.getUserId()==coachListUserDto.getUserId()){
                    dtos.add(coachListUserDto);
                }
            }
        }
        return dtos;
    }

    /**
     * 根据用户id查找用户信息
     * @param userId
     * @return
     */
    @Override
    public UserInfoDto findUserById(Integer userId) {
        UserInfo userInfo = getById(userId);
        UserInfoDto dto = BeanUtil.toBean(userInfo, UserInfoDto.class);
        return dto;
    }

    /**
     * 用户修改密码
     * @param form
     * @param userId
     */
    @Override
    public void updatePwd(UpdateUserPwdForm form, Integer userId) {
        UserInfo userInfo = getById(userId);
        if (!userInfo.getUserPass().equals(form.getOldPwd())) throw new UserInfoException(40008,"原密码不正确");
        userInfo.setUserPass(form.getNewPwd());
        updateById(userInfo);
    }

    /**
     * 管理员禁用用户
     * @param userId
     */
    @Override
    public void disabledUser(Integer userId) {
        UserInfo userInfo = getById(userId);
        if (ObjectUtils.isEmpty(userInfo)) throw new UserInfoException(40002,"用户不存在");
        if (userInfo.getUserState()==UserState.IS_DISABLED.getState()) throw new UserInfoException(40003,"用户已被禁用，重复操作");
        userInfo.setUserState(UserState.IS_DISABLED.getState());
        updateById(userInfo);
    }

    /**
     * 管理员启用用户
     * @param userId
     */
    @Override
    public void enableUser(Integer userId) {
        UserInfo userInfo = getById(userId);
        if (ObjectUtils.isEmpty(userInfo)) throw new UserInfoException(40002,"用户不存在");
        if (userInfo.getUserState()==UserState.IS_ENABLE.getState()) throw new UserInfoException(4000,"用户已启用，重复操作");
        userInfo.setUserState(UserState.IS_ENABLE.getState());
        updateById(userInfo);
    }

    /**
     * 商家端查看学员信息
     * @param form
     * @param venueId
     * @return
     */
    @Override
    public List<VenueListUserDto> venueListUser(VenueListUserForm form, Integer venueId) {
        //通过商家id查找其订单,订单中是已付了款状态的就是正在学习中的学员，如果学习完成了订单状态是已完成
        Result<List<VenueListOrderDto>> res1 = ofc.findByVenueId(venueId);
        if (!res1.getFlag()) throw new UserInfoException(res1.getCode(),res1.getMsg());
        List<VenueListOrderDto> data = res1.getData();
        if (ObjectUtils.isEmpty(data)) return null;
        //只需要状态是已付款的订单
        List<VenueListOrderDto> orders = data.stream().filter(o -> o.getOrderState() == OrderState.IS_PAID.getState()).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(orders)) return null;
        List<UserInfo> userInfos = list(new LambdaQueryWrapper<UserInfo>()
                .eq(!ObjectUtils.isEmpty(form.getUserName()), UserInfo::getUserName, form.getUserName())
                .eq(!ObjectUtils.isEmpty(form.getUserPhone()), UserInfo::getUserPhone, form.getUserPhone()));
        if (ObjectUtils.isEmpty(userInfos))  return null;

        List<VenueListUserDto> list = new ArrayList<>();
        for (VenueListOrderDto order : orders) {
            VenueListUserDto dto = BeanUtil.toBean(order, VenueListUserDto.class);
            UserInfo userInfo = getById(order.getUserId());
            dto.setUserAvatar(userInfo.getUserAvatar());
            dto.setUserName(userInfo.getUserName());
            dto.setSex(userInfo.getUserSex());
            dto.setTypeId(order.getOrderType());
            dto.setTypeName(order.getTypeName());
            list.add(dto);
        }
        List<VenueListUserDto> dtos = new ArrayList<>();
        for (UserInfo userInfo : userInfos) {
            for (VenueListUserDto venueListUserDto : list) {
                if (userInfo.getUserId()==venueListUserDto.getUserId()){
                    dtos.add(venueListUserDto);
                }
            }
        }
        return dtos;
    }

    /**
     * 用户发送登录验证码
     * @param phone
     */
    @Override
    public void userLoginSendCode(String phone) {
        //判断手机号如果存在才进入发验证码的环节
        UserInfo userInfo = getOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserPhone, phone));
        if (null == userInfo) throw new UserInfoException(40007,"手机号还未注册，请先注册");
        //查一下该手机号的验证码是否在1分钟之内
        if (myRedisUtil.exists(myRedisKeyUtil.sendLoginInMinute(phone))){
            throw new UserInfoException(40002,"短信发送过于频繁");
        }
        String total = myRedisUtil.get(myRedisKeyUtil.sendCodeTotalInHour(phone));
        if (StringUtils.hasLength(total)&&Integer.parseInt(total)>=5){
            throw new UserInfoException(40003,"1小时内发送次数超过上限");
        }
        rabbitTemplate.convertAndSend("code-send-login",phone);
    }

    /**
     * 用户发送注册验证码
     * @param phone
     */
    @Override
    public void userRegisterSendCode(String phone) {
        //查一下该手机号的验证码是否在1分钟之内
        if (myRedisUtil.exists(myRedisKeyUtil.sendRegisterInMinute(phone))){
            throw new UserInfoException(40002,"短信发送过于频繁");
        }
        String total = myRedisUtil.get(myRedisKeyUtil.sendCodeTotalInHour(phone));
        if (StringUtils.hasLength(total)&&Integer.parseInt(total)>=5){
            throw new UserInfoException(40003,"1小时内发送次数超过上限");
        }
        UserInfo userInfo = new LambdaQueryChainWrapper<UserInfo>(getBaseMapper())
                .eq(UserInfo::getUserPhone, phone).one();
        if (null!=userInfo) throw new UserInfoException(40001,"手机号已被注册");
        rabbitTemplate.convertAndSend("code_send_register",phone);
    }

    /**
     * 用户实名认证
     * @param idCardFile
     * @param userId
     * @return
     * @throws Exception
     */
    @Override
    public UserOauthDto userOauth(MultipartFile idCardFile, Integer userId) throws Exception {
        UserInfo userInfo = getById(userId);
        if(userInfo.getAuthState()==UserState.IS_AUTH.getState()) throw new UserInfoException(40003,"用户已实名认证");
        // 指定保存文件的目录
        String uploadDir = "C:\\Users\\Administrator\\Desktop\\temp";
        // 创建目标目录（如果不存在）
        File dir = new File(uploadDir);
        if (!dir.exists())  dir.mkdirs();
        String type = FileTypeUtil.getType(idCardFile.getInputStream());
        if (!type.equals("jpg")&&!type.equals("png")) throw new UserInfoException(40005,"图片格式异常");
        String fileName = new Snowflake(1, 1).nextIdStr();
        fileName = fileName+"."+type;
        // 构造保存文件的完整路径
        String filePath = uploadDir +"\\"+ fileName;
        // 将上传文件保存到指定目录
        File destFile = new File(filePath);
        idCardFile.transferTo(destFile);
        //调阿里云实名认证接口
        AuthUser authUser = null;
        try {
            authUser = ORCIdCardUtil.oauthIdCard(filePath);
        } catch (Exception e) {
            if (e instanceof TeaException) throw new WoniuxyException(500,"请上传合法的身份证正面照片");
            else throw e;
        }
        userInfo.setAuthState(UserState.IS_AUTH.getState());
        userInfo.setUserName(authUser.getName());
        userInfo.setUserSex(authUser.getSex());
        userInfo.setIdCard(authUser.getIdCardNum());
        updateById(userInfo);
        UserOauthDto dto = BeanUtil.toBean(userInfo, UserOauthDto.class);
        return dto;
    }
}
